<template>
  <div class="dept">
    <div class="header">
      <div>部门信息</div>
      <div class="operate">
        <el-button @click="reloadDeptTree">刷新</el-button>
        <el-button type="primary" @click="saveUpdate">保存更新</el-button>
      </div>
    </div>
    <div class="add-folder" @click="addNodeTreeList">
      <div class="add-folder-span">
        <svg-icon name="plus" size="30"></svg-icon>
        <div>新增一级</div>
      </div>
    </div>
    <el-tree class="tree-show" :data="deptTree" show-checkbox draggable
             v-loading="loading" empty-text="请添加部门信息"
             node-key="id" @node-click="handleNodeClick"
             @node-drop="handleNodeDrop"
             @node-collapse="nodeCollapse"
             :default-expanded-keys="defaultExpandedKeys">
      <template #default="{ node, data }">
        <div class="custom-tree-node">
          <span v-if="!data.isAddNode">{{ node.label }}</span>
          <el-dropdown class="edit-tree-dropdown" v-if="!data.isAddNode">
            <span style="border: 0">
              <a class="showEllipsis"> ... </a>
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item><span @click.stop="addAllNode(node, data)">新增</span></el-dropdown-item>
                <el-dropdown-item @click.stop="editAllNode(node, data)">编辑</el-dropdown-item>
                <el-dropdown-item @click.stop="delAllNode(node, data)">删除</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
          <!-- 点击新增时的输入框 -->
          <el-input
              v-model="newChildNode"
              v-if="data.isAddNode"
              @keyup.enter.stop.native="handleAddEnter(node, data)"
              @blur="removeTreeNode(node, data)"
              @change="handleAddNode(node, data)"
              ref="addRef"
              class="add-new-child-node">
          </el-input>
          <!-- 点击修改时的输入框 -->
          <el-input
              v-model="data.name"
              v-show="data.isEditNode"
              @change="handleEditNode(node, data)"
              @keyup.enter.stop.native="handleEditEnter(node, data)"
              class="edit-child-node">
          </el-input>
        </div>
      </template>
    </el-tree>
    <!-- 点击新增一级显示的输入框 -->
    <div class="add-input" v-if="inputShow">
      <el-input
          v-model="addNodeTree"
          placeholder="输入中"
          @change="addClassification"
          @keyup.enter.stop.native="handleEnter"
          ref="newNodeRef">
      </el-input>
    </div>
  </div>
</template>

<script lang="ts">
import { nextTick, onMounted, ref} from "vue";
import {getDepartment} from "@/api/config";
import {DragEvents} from "element-plus/es/components/tree/src/model/useDragNode";
import {NodeDropType} from "element-plus/es/components/tree/src/tree.type";
import {IDept} from "@/iwb/IConfig";
import {useConfigStore} from "@/store/config";
import {DialogUtils} from "@/utils/DialogUtils";

export default {
  name: "Department",
  setup() {
    const maxId = ref(0);
    const useConfig = useConfigStore();
    const loading = ref(false);
    const deptTree = ref([] as Array<IDept>);
    const hasChildList = (children: any) => {
      return children !== undefined && children.length > 0;
    }

    const handleDragEnter = (
        draggingNode: Node,
        dropNode: Node,
        ev: DragEvents
    ) => {
      //console.log('tree draggingNode enter:', draggingNode)
      //console.log('tree dropNode enter:', dropNode)
    }

    const handleDragEnd = (
        draggingNode: Node,
        dropNode: Node,
        dropType: NodeDropType,
        ev: DragEvents
    ) => {
      //console.log('tree drag end:', dropNode && dropNode.label, dropType);
      //console.warn(deptTree.value);
    }

    const updateMaxId = (item: IDept) => {
      maxId.value = item.id > maxId.value ? item.id : maxId.value;
    }

    const withChildDepartment = (children: any) => {
      children.forEach((item: any) => {
        item.label = item.name;
        updateMaxId(item);
        if(hasChildList(item.children)) {
          withChildDepartment(item.children);
        }
      })
    }
    const reloadDeptTree = () => {
      maxId.value = 0;
      loading.value = true;
      deptTree.value = [] as Array<IDept>;
      getDepartment().then(res => {
        deptTree.value = res.data;
        deptTree.value.forEach(item => {
          item.label = item.name;
          updateMaxId(item);
          withChildDepartment(item.children);
        })
        loading.value = false;
      }).catch(error => {
        console.error(error);
        loading.value = false;
      })
    }
    /**
     * 获取部门的唯一ID
     */
    const createDeptId = (): number => {
      maxId.value += 1;
      return maxId.value;
    }
    /**
     * 获取部门的在本级部门的排序，越小排前面
     * @param node
     */
    const createCode = (node: any): number => {
      if (node && node.children && node.children.length > 0) {
        let index = -1 + node.children.length;
        return node.children[index].code;
      }
      return 0;
    }
    onMounted(() => {
      reloadDeptTree();
    });
    /**
     * 部门信息更新，保存
     */
    const saveUpdate = () => {

    }

    //点击树节点时触发的方法
    const parentId = ref(0);
    const handleNodeClick = (node: any, data: IDept) => {
      //console.log(node)
      //console.log(node);
      parentId.value = node.parentId;
    };

    //节点被关闭时触发的事件，节点关闭时输入框也消失
    const nodeCollapse = (data: IDept) => {
      //console.log("data: ", data);
      // 如果有input框, 删除节点
      if (nodeShow.value) {
        data.children.pop();
        nodeShow.value = false;
      }
    };

    //点击新增，出现输入框
    const nodeShow = ref(false);
    const addRef = ref(HTMLInputElement);
    const newChildNode = ref("");
    const addAllNode = (node: any, data: IDept) => {
      //console.log(node);
      if (nodeShow.value) return;
      nodeShow.value = true;
      if (!data.children || !Array.isArray(data.children)) {
        data.children = [];
      }
      // 展开
      //console.log("treeRef.value: ", data.id, treeRef.value);
      //使树形结构图展开
      node.expanded = true;
      //为了使输入框出现在最下层。为树结构添加节点
      nextTick(() => {
        let newNode = {} as IDept;
        newNode.id = createDeptId();
        newNode.name = newChildNode.value;
        newNode.parentId = data.id;
        newNode.code = createCode(node);
        newNode.isAddNode = true;
        data.children.push(newNode);
        setTimeout(() => {
          // @ts-ignore
          addRef.value && addRef.value.focus();
        }, 800);
      });
      //console.log("data: ", data);
    };
    //点击编辑，出现输入框
    const editAllNode = (node: any, data: IDept) => {
      nextTick(() => {
        data.isEditNode = true;
      });
    };
    //删除节点
    const delAllNode = (node: any, data: IDept) => {
      useConfig.deleteDepartment(data.id).then(res=>{
        reloadDeptTree();
      }).catch(error => {
        console.error(error);
      })
    };
    // 删除节点。添加完节点后删除节点
    function removeTreeNode(node: any, data: IDept) {
      const parent = node.parent;
      const children = parent.data.children || parent.data;
      const index = children.findIndex((d: any) => d.id === data.id);
      children.splice(index, 1);
      deptTree.value = [...deptTree.value];
      nodeShow.value = false;
    }

    //输入框输入内容添加数据
    const defaultExpandedKeys = ref([]);
    const handleAddNode = (node: any, data: IDept) => {
      //console.log(node)
      //console.log(data);
      let parentId = node.data.parentId;
      // @ts-ignore
      defaultExpandedKeys.value.push(node.data.parentId);
      const dept = {} as IDept;
      dept.id = createDeptId();
      dept.name = newChildNode.value;
      dept.parentId = parentId ? parentId : 0;
      dept.code = createCode(node);

      useConfig.addDepartment(dept).then((res: any) => {
        //console.warn(res);
        nextTick(() => {
          data.isAddNode = false;
          // @ts-ignore
          addRef.value && addRef.value.focus();
        });
        reloadDeptTree();
        newChildNode.value = "";
      }).catch(error => {
        console.error(error);
      })
    };
    //此方法为用户在输入框不输入任何东西时回车输入框不显示
    const handleAddEnter = (node: any, data: IDept) => {
      if(data.isAddNode) return
      nextTick(() => {
        data.isAddNode = false;
        // @ts-ignore
        addRef.value && addRef.value.focus();
      });
    };

    //编辑完之后请求接口保存编辑完的数据
    const handleEditNode = (node: any, data: IDept) => {
      //console.log("node: ", node);
      //console.log(data);
      const dept = {} as IDept;
      dept.id =  data.id;
      dept.name = data.name;
      dept.parentId = data.parentId;
      dept.code = data.code;

      useConfig.editDepartment(dept).then((res) => {
        nextTick(() => {
          data.isEditNode = false;
        });
        reloadDeptTree();
      }).catch(err => {
        console.error(err);
      })
    };
    //此方法为用户在输入框不输入任何东西时回车输入框不显示
    const handleEditEnter = (node: any, data: IDept) => {
      nextTick(() => {
        data.isEditNode = false;
      });
    };

    // 点击新增一级（新增一级时parentid默认为0）
    const newNodeRef = ref(HTMLInputElement);
    const addNodeTree = ref("");
    const inputShow = ref(false);
    const addNodeTreeList = () => {
      nextTick(() => {
        inputShow.value = true;
        setTimeout(() => {
          // @ts-ignore
          newNodeRef.value && newNodeRef.value.focus();
        }, 800);
      })
    };

    //新增一级出现输入框时通过change事件输入内容请求方法添加节点
    const addClassification = () => {
      const data = {} as IDept;
      data.id = createDeptId();
      data.name = addNodeTree.value;
      data.parentId = 0;
      data.code = createCode(null);

      //console.log(addNodeTree.value === "");
      if (addNodeTree.value != "") {
        useConfig.addDepartment(data).then((res: any) => {
          inputShow.value = false;
          reloadDeptTree();
          addNodeTree.value = "";
        })
      } else {
        inputShow.value = false;
      }
    };
    //此方法为用户在输入框不输入任何东西时回车输入框不显示
    const handleEnter = () => {
      inputShow.value = false;
    };

    //拖曳节点成功时调用
    const handleNodeDrop = (sNode: any, tNode: any, position: string) => {
      const currNode = {} as IDept;
      currNode.id = sNode.data.id;
      if (position === 'inner') {
        currNode.parentId = tNode.data.id;
      } else if (position === 'before') {
        currNode.parentId = tNode.data.parentId;
        currNode.code = tNode.data.code - 1;
      } else if (position === 'after') {
        currNode.parentId = tNode.data.parentId;
        currNode.code = tNode.data.code + 1;
      } else {
        DialogUtils.showErrorBox('错误提示', '移动异常情况');
        return;
      }
      useConfig.editDepartment(currNode).then(()=>{
        reloadDeptTree();
      }).catch(error => {
        console.error(error);
        DialogUtils.showErrorBox('错误提示', '拖动更新失败');
      })
    }

    return {
      loading,
      deptTree,
      addRef,
      newChildNode,
      addNodeTree,
      defaultExpandedKeys,
      inputShow,
      handleDragEnter,
      handleDragEnd,
      reloadDeptTree,
      saveUpdate,
      addNodeTreeList,
      addAllNode,
      editAllNode,
      delAllNode,
      removeTreeNode,
      handleAddNode,
      handleAddEnter,
      handleEditNode,
      handleEditEnter,
      addClassification,
      handleEnter,
      handleNodeClick,
      nodeCollapse,
      handleNodeDrop
    }
  }
}
</script>

<style scoped lang="scss">
@import "src/styles/variable";
.dept {
  width: auto;
  height: calc(100% - 20px);
  margin: 10px;
  background-color: $color-sub-background-base;
  box-sizing: border-box;
  border: 0;
  border-radius: 5px;
  overflow-y: auto;
  .header {
    padding: 10px 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid $color-border-base;
  }
  .operate {
    display: flex;
    justify-content: flex-end;
    align-items: center;
  }
  //树的定义
  .add-folder-span {
    display: flex;
    align-items: center;
    padding: 2px 15px;
    cursor: pointer;
  }
  .add-folder {
    line-height: 32px;
    height: 32px;
    font-size: 14px;
    cursor: pointer;
    border-left: 3px solid transparent;
    .add-folder-span {
      background-repeat: no-repeat;
      background-position: 0px 50%;
      margin-left: 8px;
      color: #5d63da;
    }
  }

  .el-input {
    padding-left: 20px;
    :deep(.el-input__wrapper) {
      width: 240px;
      height: 28px;
      background: rgba(255, 255, 255, 0.6);
      border-radius: 8px;
      border: 1px solid #e1e1f0;
      margin-right: 20px;
      margin-top: 10px;
    }
    :deep(.el-input__inner) {
      font-size: 12px;
      color: #8894a8;
    }
  }

  .tree-show {
    padding-left: 15px;
    overflow-y: auto;
    height: calc(100% - 180px);

    ::v-deep {
      /* 设置树形最外层的背景颜色和字体颜色 */
      .is-leaf::before {
        display: none;
      }
    }
  }
  .el-tree {
    position: relative;
    background: none;

    :deep(.el-tree-node) {
      position: relative;
    }

    :deep(.el-tree-node__content) {
      height: 34px !important;

      .el-input__wrapper {
        margin-top: 0;
      }

      .custom-tree-node {
        position: relative;
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding-right: 20px;
        width: 100%;
        font-size: 14px;

        .edit-tree-dropdown {
          position: relative;
          visibility: hidden;

          .showEllipsis {
            width: 18px;
            height: 18px;
            background: #fff;
            border-radius: 50%;
            vertical-align: text-top;
            line-height: 14px;
            display: block;
            text-align: center;
            color: #5d63da;
            border: 0;
          }
        }
      }

      //此处为鼠标输入时显示三个点
      &:hover {
        .custom-tree-node {
          .edit-tree-dropdown {
            visibility: visible;
          }
        }
      }
    }
  }

  .add-new-child-node {
    z-index: 20;
    width: calc(100% - 10px);
    padding-left: 0px;
    background: rgba(255, 255, 255, 0.6);
    :deep(.el-input__wrapper) {
      background: #fff;
    }
  }
  .edit-child-node {
    width: calc(100% - 10px);
    background: rgba(255, 255, 255, 0.6);
    position: absolute;
    padding-left: 10px;
    left: -15px;
    // top: 0;
    :deep(.el-input__wrapper) {
      background: #fff;
    }
  }
  .department {
    display: flex;
    flex-direction: row;
  }
}
</style>